import { Vector3 } from 'three-legacy';

/**
 * 判断两条直线是否共面（基于四个点输入）
 * @param {THREE.Vector3} p1 - 第一条直线的起点
 * @param {THREE.Vector3} p2 - 第一条直线的终点
 * @param {THREE.Vector3} p3 - 第二条直线的起点
 * @param {THREE.Vector3} p4 - 第二条直线的终点
 * @param {number} [epsilon=1e-10] - 浮点比较的容差
 * @returns {boolean} - 是否共面
 */
export function areLinesCoplanar(
  p1: Vector3,
  p2: Vector3,
  p3: Vector3,
  p4: Vector3,
  epsilon: number = 1e-8,
): boolean {
  // 克隆点以避免修改原始数据
  const point1 = p1.clone();
  const point2 = p2.clone();
  const point3 = p3.clone();
  const point4 = p4.clone();

  // 计算方向向量
  const v1 = new Vector3().subVectors(point2, point1);
  const v2 = new Vector3().subVectors(point4, point3);

  // 检查零向量（直线退化为点）
  const isLine1Point = v1.lengthSq() < epsilon;
  const isLine2Point = v2.lengthSq() < epsilon;

  // 情况1：两条直线都退化为点
  if (isLine1Point && isLine2Point) {
    // 两点重合则认为共面
    return point1.distanceTo(point3) < epsilon;
  }

  // 情况2：只有一条直线退化为点
  if (isLine1Point || isLine2Point) {
    const point = isLine1Point ? point1 : point3;
    const lineStart = isLine1Point ? point3 : point1;
    const lineVec = isLine1Point ? v2 : v1;

    // 计算点到直线的距离
    const pointToLine = new Vector3().subVectors(point, lineStart);
    const cross = new Vector3().crossVectors(lineVec, pointToLine);
    const distance = cross.length() / lineVec.length();

    // 如果点在直线上或距离非常小，则认为共面
    return distance < epsilon;
  }

  // 检查平行性（包括同向和反向）
  const crossV1V2 = new Vector3().crossVectors(v1, v2);
  const areParallel = crossV1V2.lengthSq() < epsilon;

  // 情况3：两条直线平行
  if (areParallel) {
    // 平行直线总是共面。 注: 如果这两条线在同一条直线上，这情况这个函数不判断。
    return true;
  }

  // 情况4：一般情况（不平行），使用标量三重积判断
  const p1p3 = new Vector3().subVectors(point3, point1);
  const tripleProduct = v1.dot(new Vector3().crossVectors(v2, p1p3));

  // 标量三重积为零表示共面
  return Math.abs(tripleProduct) < epsilon;
}

/**
 * 判断多段线是否是一条直线
 * @param points
 * @param epsilon
 * @returns
 */
export function isPolylineStraight(points: Array<Vector3>, epsilon = 1e-6) {
  if (points.length < 3) return true;

  const p0 = points[0];
  const p1 = points[1];
  const v1 = new Vector3().subVectors(p1, p0);

  for (let i = 2; i < points.length; i++) {
    const v2 = new Vector3().subVectors(points[i], p0);
    const cross = new Vector3().crossVectors(v1, v2);

    // 如果叉积长度不为0，说明不共线
    if (cross.length() > epsilon) {
      return false;
    }
  }

  return true;
}

/**
 * 判断多段线是否共面，这里默认的精度不设置太高。
 * @param points
 * @param epsilon
 * @returns
 */
export function isPolylinePlanar(points: Array<Vector3>, epsilon = 1e-4) {
  if (points.length < 3) return true; // 少于3个点总是共面

  const p0 = points[0];
  const p1 = points[1];
  const p2 = points[2];

  // 计算两个向量
  const v1 = new Vector3().subVectors(p1, p0);
  const v2 = new Vector3().subVectors(p2, p0);

  // 计算法向量(叉积)
  const normal = new Vector3().crossVectors(v1, v2);

  // 如果法向量长度为0，说明前三点共线，需要找不共线的三点
  if (normal.length() < epsilon) {
    // 需要找到三个不共线的点来定义平面
    for (let i = 2; i < points.length; i++) {
      const v = new Vector3().subVectors(points[i], p0);
      const tempNormal = new Vector3().crossVectors(v1, v);
      if (tempNormal.length() >= epsilon) {
        normal.copy(tempNormal);
        break;
      }
    }
    // 如果所有点都共线，则它们共面
    if (normal.length() < epsilon) return true;
  }

  // 平面方程: normal · (p - p0) = 0
  for (let i = 3; i < points.length; i++) {
    const p = points[i];
    const v = new Vector3().subVectors(p, p0);
    const distance = Math.abs(normal.dot(v));
    if (distance > epsilon) {
      return false;
    }
  }

  return true;
}

/**
 * 判断曲线列表（每条曲线为点数组）是否能组成一条闭合的曲线（端点重合数为偶数）
 * @param curves - 曲线列表，每条曲线为 Vector3[]
 * @param epsilon - 浮点比较的容差，默认为1e-3
 * @returns 是否能组成闭合曲线
 */
export function canCurvesFormClosedLoop(
  curves: Vector3[][],
  epsilon = 1e-3,
): boolean {
  if (curves.length === 0) return false;
  if (curves.length === 1) {
    const curve = curves[0];
    if (curve.length < 3) return false;
    const firstPoint = curve[0];
    const lastPoint = curve[curve.length - 1];
    return firstPoint.distanceTo(lastPoint) < epsilon;
  }

  // 统计所有端点
  const endpoints: Vector3[] = [];
  for (const curve of curves) {
    if (curve.length < 2) return false;
    endpoints.push(curve[0]);
    endpoints.push(curve[curve.length - 1]);
  }

  // 统计每个端点的重合次数
  const used = new Array(endpoints.length).fill(false);
  let unmatched = 0;

  for (let i = 0; i < endpoints.length; i++) {
    if (used[i]) continue;
    let count = 1;
    used[i] = true;
    for (let j = i + 1; j < endpoints.length; j++) {
      if (!used[j] && endpoints[i].distanceTo(endpoints[j]) < epsilon) {
        used[j] = true;
        count++;
      }
    }
    if (count % 2 !== 0) {
      unmatched++;
    }
  }

  // 所有端点重合数都为偶数才可闭合
  return unmatched === 0;
}
